package com.lj.file.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.lj.common.utils.excel.ExcelSheet;
import com.lj.common.utils.excel.ExcelUtil;
import com.lj.file.entity.FileDetail;
import com.lj.file.entity.FilePartDetail;
import com.lj.file.enums.UploadStatus;
import com.lj.file.mapper.FileDetailMapper;
import com.lj.file.param.FileDetailPageParam;
import com.lj.file.result.FileDetailExportResult;
import com.lj.file.result.FileDetailInfoResult;
import com.lj.file.result.FileDetailPageResult;
import com.lj.file.service.FileDetailService;
import com.lj.file.service.FilePartDetailService;
import com.lj.mp.standard.StandardServiceImpl;
import com.lj.mp.utils.PageQueryUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.recorder.FileRecorder;
import org.dromara.x.file.storage.core.upload.FilePartInfo;
import org.springframework.stereotype.Service;

import java.io.OutputStream;
import java.util.List;

/**
 * <p>
 * 文件记录表 服务实现类
 * </p>
 *
 * @author lj
 * @since 2025-06-26 16:30:45
 */
@Service
@Slf4j
public class FileDetailServiceImpl extends StandardServiceImpl<FileDetailMapper, FileDetail> implements FileDetailService, FileRecorder {

    @Resource
    private FilePartDetailService partDetailService;

    @Override
    public IPage<FileDetailPageResult> page(FileDetailPageParam param) {
        return this.page(PageQueryUtils.getPage(param), getQueryWrapper(param)).convert(FileDetailPageResult::of);
    }

    private LambdaQueryWrapper<FileDetail> getQueryWrapper(FileDetailPageParam param) {
        return lambdaQueryWrapper()
                .eq(ObjectUtil.isNotEmpty(param.getOriginalFilename()), FileDetail::getOriginalFilename, param.getOriginalFilename())
                .orderByDesc(CollUtil.isEmpty(param.getSortList()), FileDetail::getId);
    }

    @Override
    public FileDetailInfoResult info(Long id) {
        FileDetail detail = this.getById(id);
        if (detail == null) {
            return null;
        }
        FileDetailInfoResult result = FileDetailInfoResult.of(detail);
        if (UploadStatus.INIT.equals(detail.getUploadStatus())) {
            // 还在分片上传中，列举出分片上传的分片号
            result.setChunkNumberList(partDetailService.getParts(detail.getUploadId())
                    .stream()
                    .map(FilePartDetail::getPartNumber)
                    .sorted()
                    .toList());
        }
        return result;
    }

    @Override
    public void exportExcel(FileDetailPageParam param, OutputStream out) {
        List<FileDetail> dataList = this.list(getQueryWrapper(param));
        List<FileDetailExportResult> exportList = dataList.stream().map(FileDetailExportResult::of).toList();
        ExcelUtil.writeExcel(out, new ExcelSheet<>(exportList, FileDetailExportResult.class));
    }

    /**
     * 保存文件信息到数据库
     */
    @Override
    public boolean save(FileInfo fileInfo) {
        fileInfo.setId(IdWorker.getIdStr());
        if (fileInfo.getUploadStatus() == null) {
            // 普通上传(不是分片上传) 将上传状态设置为已完成
            fileInfo.setUploadStatus(UploadStatus.FINISHED.getValue());
        }
        return this.save(toFileDetail(fileInfo));
    }

    /**
     * 更新文件记录，可以根据文件 ID 或 URL 来更新文件记录，
     * 主要用在手动分片上传文件-完成上传，作用是更新文件信息
     */
    @Override
    public void update(FileInfo fileInfo) {
        FileDetail detail = toFileDetail(fileInfo);
        update(detail, lambdaQueryWrapper()
                .eq(detail.getUrl() != null, FileDetail::getUrl, detail.getUrl())
                .eq(detail.getId() != null, FileDetail::getId, detail.getId()));
    }

    /**
     * 根据 url 查询文件信息
     */
    @Override
    public FileInfo getByUrl(String url) {
        if (StrUtil.isBlank(url)) {
            return null;
        }
        return toFileInfo(this.getOne(lambdaQueryWrapper()
                .eq(FileDetail::getUrl, url)
                .last("limit 1")));
    }

    @Override
    public boolean delete(String url) {
//        remove(lambdaQueryWrapper().eq(FileDetail::getUrl, url));
        // 这里并不真实删除数据库，上面的批量删除已经进行删除了
        return true;
    }

    @Override
    public void saveFilePart(FilePartInfo filePartInfo) {
        // 保存文件分片信息
        FilePartDetail detail = toFilePartDetail(filePartInfo);
        if (partDetailService.save(detail)) {
            filePartInfo.setId(StrUtil.toString(detail.getId()));
        }
    }

    @Override
    public void deleteFilePartByUploadId(String uploadId) {
        partDetailService.deleteFilePartByUploadId(uploadId);
    }
}
